package com.example.vaultmysql.service;

import com.example.vaultmysql.entity.TestExecution;
import com.example.vaultmysql.entity.DatabaseConfig;
import com.example.vaultmysql.repository.TestExecutionRepository;
import com.example.vaultmysql.repository.DatabaseConfigRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 高并发测试服务
 * 负责执行数据库高并发测试
 * 
 * @author System
 * @version 1.0.0
 */
@Slf4j
@Service
public class ConcurrencyTestService {

    @Autowired
    private TestExecutionRepository testExecutionRepository;

    @Autowired
    private DatabaseConfigRepository databaseConfigRepository;

    @Autowired
    private DatabaseConnectionService databaseConnectionService;

    private final Map<Long, Future<?>> runningTests = new ConcurrentHashMap<>();
    private final ExecutorService testExecutor = Executors.newCachedThreadPool();

    /**
     * 启动高并发测试
     */
    @Async
    public CompletableFuture<TestExecution> startConcurrencyTest(
            String testName,
            List<String> databaseNames,
            int concurrentUsers,
            int durationSeconds,
            TestExecution.QueryType queryType,
            String creator) {
        
        // 创建测试执行记录
        TestExecution testExecution = new TestExecution();
        testExecution.setTestName(testName);
        testExecution.setStatus(TestExecution.TestStatus.RUNNING);
        testExecution.setConcurrentUsers(concurrentUsers);
        testExecution.setDurationSeconds(durationSeconds);
        testExecution.setQueryType(queryType);
        testExecution.setStartTime(LocalDateTime.now());
        testExecution.setCreatedBy(creator);
        testExecution.setCreatedAt(LocalDateTime.now());
        
        testExecution = testExecutionRepository.save(testExecution);
        
        // 异步执行测试
        Future<?> testFuture = testExecutor.submit(() -> {
            try {
                executeTest(testExecution, databaseNames);
            } catch (Exception e) {
                log.error("测试执行失败: testId={}", testExecution.getId(), e);
                testExecution.setStatus(TestExecution.TestStatus.FAILED);
                testExecution.setEndTime(LocalDateTime.now());
                testExecutionRepository.save(testExecution);
            }
        });
        
        runningTests.put(testExecution.getId(), testFuture);
        
        return CompletableFuture.completedFuture(testExecution);
    }

    /**
     * 执行测试
     */
    private void executeTest(TestExecution testExecution, List<String> databaseNames) {
        log.info("开始执行高并发测试: testId={}, databases={}, users={}, duration={}s", 
                testExecution.getId(), databaseNames, testExecution.getConcurrentUsers(), 
                testExecution.getDurationSeconds());
        
        try {
            // 验证数据库配置
            List<DatabaseConfig> databases = new ArrayList<>();
            for (String dbName : databaseNames) {
                DatabaseConfig config = databaseConfigRepository.findByName(dbName)
                        .orElseThrow(() -> new IllegalArgumentException("数据库配置不存在: " + dbName));
                if (!config.getEnabled()) {
                    throw new IllegalStateException("数据库已禁用: " + dbName);
                }
                databases.add(config);
            }
            
            // 创建线程池
            ExecutorService executor = Executors.newFixedThreadPool(testExecution.getConcurrentUsers());
            
            // 测试统计
            AtomicLong totalRequests = new AtomicLong(0);
            AtomicLong successfulRequests = new AtomicLong(0);
            AtomicLong failedRequests = new AtomicLong(0);
            AtomicLong totalResponseTime = new AtomicLong(0);
            
            List<Long> responseTimes = Collections.synchronizedList(new ArrayList<>());
            
            // 启动测试线程
            List<Future<?>> futures = new ArrayList<>();
            long testEndTime = System.currentTimeMillis() + (testExecution.getDurationSeconds() * 1000L);
            
            for (int i = 0; i < testExecution.getConcurrentUsers(); i++) {
                final int threadId = i;
                Future<?> future = executor.submit(() -> {
                    Random random = new Random();
                    
                    while (System.currentTimeMillis() < testEndTime && 
                           testExecution.getStatus() == TestExecution.TestStatus.RUNNING) {
                        
                        // 随机选择数据库
                        DatabaseConfig database = databases.get(random.nextInt(databases.size()));
                        
                        long startTime = System.currentTimeMillis();
                        boolean success = false;
                        
                        try {
                            success = executeQuery(database.getName(), testExecution.getQueryType());
                            successfulRequests.incrementAndGet();
                        } catch (Exception e) {
                            log.debug("查询执行失败: thread={}, database={}, error={}", 
                                    threadId, database.getName(), e.getMessage());
                            failedRequests.incrementAndGet();
                        }
                        
                        long responseTime = System.currentTimeMillis() - startTime;
                        totalRequests.incrementAndGet();
                        totalResponseTime.addAndGet(responseTime);
                        responseTimes.add(responseTime);
                        
                        // 短暂休息，避免过度压力
                        try {
                            Thread.sleep(10 + random.nextInt(20)); // 10-30ms随机间隔
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                });
                futures.add(future);
            }
            
            // 等待所有线程完成
            for (Future<?> future : futures) {
                try {
                    future.get();
                } catch (Exception e) {
                    log.error("测试线程执行异常", e);
                }
            }
            
            executor.shutdown();
            
            // 计算测试结果
            long totalReqs = totalRequests.get();
            long successReqs = successfulRequests.get();
            long failedReqs = failedRequests.get();
            
            double successRate = totalReqs > 0 ? (double) successReqs / totalReqs * 100 : 0;
            double avgResponseTime = totalReqs > 0 ? (double) totalResponseTime.get() / totalReqs : 0;
            double throughput = (double) totalReqs / testExecution.getDurationSeconds();
            
            // 计算响应时间百分位数
            responseTimes.sort(Long::compareTo);
            long p50 = getPercentile(responseTimes, 50);
            long p95 = getPercentile(responseTimes, 95);
            long p99 = getPercentile(responseTimes, 99);
            
            // 更新测试结果
            testExecution.setStatus(TestExecution.TestStatus.COMPLETED);
            testExecution.setEndTime(LocalDateTime.now());
            
            // 这里可以保存详细的测试结果到数据库
            log.info("测试完成: testId={}, 总请求={}, 成功={}, 失败={}, 成功率={:.2f}%, " +
                    "平均响应时间={:.2f}ms, 吞吐量={:.2f}req/s, P50={}ms, P95={}ms, P99={}ms",
                    testExecution.getId(), totalReqs, successReqs, failedReqs, successRate,
                    avgResponseTime, throughput, p50, p95, p99);
            
        } catch (Exception e) {
            log.error("测试执行异常: testId={}", testExecution.getId(), e);
            testExecution.setStatus(TestExecution.TestStatus.FAILED);
            testExecution.setEndTime(LocalDateTime.now());
        } finally {
            testExecutionRepository.save(testExecution);
            runningTests.remove(testExecution.getId());
        }
    }

    /**
     * 执行查询
     */
    private boolean executeQuery(String databaseName, TestExecution.QueryType queryType) throws Exception {
        try (Connection connection = databaseConnectionService.getConnection(databaseName)) {
            String sql = getQuerySql(queryType);
            
            try (PreparedStatement stmt = connection.prepareStatement(sql)) {
                if (queryType == TestExecution.QueryType.SELECT) {
                    try (ResultSet rs = stmt.executeQuery()) {
                        return rs.next(); // 确保有结果
                    }
                } else {
                    return stmt.executeUpdate() >= 0;
                }
            }
        }
    }

    /**
     * 获取查询SQL
     */
    private String getQuerySql(TestExecution.QueryType queryType) {
        switch (queryType) {
            case SELECT:
                return "SELECT 1 as test_value, NOW() as current_time";
            case INSERT:
                return "INSERT INTO test_table (name, value, created_at) VALUES ('test', RAND(), NOW())";
            case UPDATE:
                return "UPDATE test_table SET value = RAND(), updated_at = NOW() WHERE id = FLOOR(RAND() * 1000) + 1";
            case DELETE:
                return "DELETE FROM test_table WHERE id = FLOOR(RAND() * 1000) + 1 LIMIT 1";
            default:
                return "SELECT 1";
        }
    }

    /**
     * 计算百分位数
     */
    private long getPercentile(List<Long> sortedList, int percentile) {
        if (sortedList.isEmpty()) return 0;
        
        int index = (int) Math.ceil(sortedList.size() * percentile / 100.0) - 1;
        index = Math.max(0, Math.min(index, sortedList.size() - 1));
        
        return sortedList.get(index);
    }

    /**
     * 停止测试
     */
    public boolean stopTest(Long testId) {
        try {
            TestExecution testExecution = testExecutionRepository.findById(testId)
                    .orElseThrow(() -> new IllegalArgumentException("测试不存在: " + testId));
            
            if (testExecution.getStatus() != TestExecution.TestStatus.RUNNING) {
                return false;
            }
            
            // 停止测试
            testExecution.setStatus(TestExecution.TestStatus.STOPPED);
            testExecution.setEndTime(LocalDateTime.now());
            testExecutionRepository.save(testExecution);
            
            // 取消正在运行的任务
            Future<?> future = runningTests.remove(testId);
            if (future != null) {
                future.cancel(true);
            }
            
            log.info("测试已停止: testId={}", testId);
            return true;
        } catch (Exception e) {
            log.error("停止测试失败: testId={}", testId, e);
            return false;
        }
    }

    /**
     * 获取测试状态
     */
    public TestExecution getTestStatus(Long testId) {
        return testExecutionRepository.findById(testId).orElse(null);
    }

    /**
     * 获取正在运行的测试
     */
    public List<TestExecution> getRunningTests() {
        return testExecutionRepository.findByStatus(TestExecution.TestStatus.RUNNING);
    }

    /**
     * 获取测试历史
     */
    public List<TestExecution> getTestHistory(int limit) {
        return testExecutionRepository.findTop10ByOrderByCreatedAtDesc();
    }

    /**
     * 清理完成的测试记录
     */
    public void cleanupCompletedTests(int daysOld) {
        LocalDateTime cutoffDate = LocalDateTime.now().minusDays(daysOld);
        List<TestExecution> oldTests = testExecutionRepository
                .findByStatusInAndCreatedAtBefore(
                    Arrays.asList(TestExecution.TestStatus.COMPLETED, 
                                TestExecution.TestStatus.FAILED,
                                TestExecution.TestStatus.STOPPED),
                    cutoffDate
                );
        
        if (!oldTests.isEmpty()) {
            testExecutionRepository.deleteAll(oldTests);
            log.info("清理了 {} 个旧的测试记录", oldTests.size());
        }
    }

    /**
     * 获取测试统计信息
     */
    public Map<String, Object> getTestStatistics() {
        long totalTests = testExecutionRepository.count();
        long runningTests = testExecutionRepository.countByStatus(TestExecution.TestStatus.RUNNING);
        long completedTests = testExecutionRepository.countByStatus(TestExecution.TestStatus.COMPLETED);
        long failedTests = testExecutionRepository.countByStatus(TestExecution.TestStatus.FAILED);
        
        return Map.of(
            "totalTests", totalTests,
            "runningTests", runningTests,
            "completedTests", completedTests,
            "failedTests", failedTests,
            "successRate", totalTests > 0 ? (double) completedTests / totalTests * 100 : 0
        );
    }

    /**
     * 创建简单的性能测试
     */
    public CompletableFuture<TestExecution> createSimplePerformanceTest(
            String databaseName, int concurrentUsers, int durationSeconds) {
        
        return startConcurrencyTest(
            "简单性能测试-" + databaseName,
            Arrays.asList(databaseName),
            concurrentUsers,
            durationSeconds,
            TestExecution.QueryType.SELECT,
            "system"
        );
    }
}